`include "instructions.vh"

module decode2(
        // from previous stage
        input           i_pipe_valid,
        input   [31:0]  i_pipe_instr,
        input   [16:0]  i_pipe_instr_class,

        // to next stage
        output          o_pipe_valid,
        output  [31:2]  o_pipe_pc,
        output  [31:0]  o_pipe_instr,
        output  [31:0]  o_pipe_retaddr,
        output  [ 3:0]  o_pipe_cond,
        output  [ 3:0]  o_pipe_gpr_rn_sel,
        output  [ 3:0]  o_pipe_gpr_rd_sel, // cgen: fb=true
        output          o_pipe_gpr_rd_sel_usr,
        output  [ 3:0]  o_pipe_gpr_rs_sel,
        output  [ 3:0]  o_pipe_gpr_rm_sel,
        output          o_pipe_gpr_we0,
        output  [ 3:0]  o_pipe_gpr_wa0,
        output          o_pipe_gpr_wa0_exc,
        output          o_pipe_gpr_dsel0_ex1,
        output  [ 1:0]  o_pipe_gpr_dsel0_ex2,
        output  [ 1:0]  o_pipe_gpr_dsel0_ex3,
        output  [ 1:0]  o_pipe_gpr_dsel0_wb,
        output          o_pipe_gpr_we1,
        output  [ 3:0]  o_pipe_gpr_wa1, // cgen: fb=true
        output          o_pipe_gpr_wa1_usr,
        output          o_pipe_gpr_dsel1,
        output  [ 3:0]  o_pipe_alu_op,
        output          o_pipe_shifter_operand_imm,
        output          o_pipe_cpsr_nzcv_we,
        output  [ 1:0]  o_pipe_cpsr_nzcv_dsel,
        output  [ 2:0]  o_pipe_cpsr_aif_we,
        output  [ 1:0]  o_pipe_cpsr_aif_dsel,
        output  [ 2:0]  o_pipe_cpsr_aif_d_imm,
        output          o_pipe_cpsr_mode_we,
        output  [ 1:0]  o_pipe_cpsr_mode_dsel,
        output  [ 4:0]  o_pipe_cpsr_mode_d_imm,
        output          o_pipe_cpsr_priv,
        output          o_pipe_spsr_we,
        output          o_pipe_spsr_dsel,
        output          o_pipe_ls,
        output          o_pipe_ls_store,
        output  [ 2:0]  o_pipe_ls_addr_offset_sel,
        output  [ 1:0]  o_pipe_ls_addr_sel,
        output          o_pipe_ls_part,
        output          o_pipe_ls_half,
        output          o_pipe_ls_ld_sign_ext,
        output          o_pipe_ls_double,
        output          o_pipe_lsm,
        output  [15:0]  o_pipe_lsm_reglist, // cgen: fb=true
        output  [ 4:0]  o_pipe_lsm_regcnt_tot,
        output  [ 4:0]  o_pipe_lsm_regcnt_dec, // cgen: fb=true
        output  [ 3:0]  o_pipe_lsm_regcnt_inc, // cgen: fb=true
        output          o_pipe_branch_ex1,
        output  [ 1:0]  o_pipe_branch_ex1_dest_sel,
        output  [ 4:2]  o_pipe_branch_ex1_dest_imm,
        output          o_pipe_branch_wb,
        output          o_pipe_branch_wb_dest_sel,
        output          o_pipe_mul,
        output          o_pipe_mul_long,
        output          o_pipe_mul_sign,
        output          o_pipe_mul_add,
        output  [ 1:0]  o_pipe_ext_rot,
        output  [ 1:0]  o_pipe_ext_op,
        output          o_pipe_ext_sign,
        output          o_pipe_ext_add,
        output          o_pipe_coproc_sel,
        output  [ 3:0]  o_pipe_coproc_cp_num,
        output  [ 2:0]  o_pipe_coproc_op1,
        output  [ 2:0]  o_pipe_coproc_op2,
        output  [ 3:0]  o_pipe_coproc_crn,
        output  [ 3:0]  o_pipe_coproc_crm,

        // from pc
        input   [31:2]  i_pc,

        // pipeline control
        output          o_valid
);

wire [4:0] lsm_regcnt_tot;
wire [14:0] read_gpr;

wire read_rn;
wire [3:0] rn_sel;
wire read_rd;
wire [3:0] rd_sel;
wire rd_sel_usr;
wire read_rs;
wire [3:0] rs_sel;
wire read_rm;
wire [3:0] rm_sel;
wire read_nzcv;
wire read_spsr;
wire gpr_we0;
wire [3:0] gpr_wa0;
wire gpr_wa0_exc;
wire gpr_dsel0_ex1;
wire [1:0] gpr_dsel0_ex2;
wire [1:0] gpr_dsel0_ex3;
wire [1:0] gpr_dsel0_wb;
wire gpr_we1;
wire [3:0] gpr_wa1;
wire gpr_wa1_usr;
wire gpr_dsel1;
wire cpsr_nzcv_we;
wire [1:0] cpsr_nzcv_dsel;
wire [2:0] cpsr_aif_we;
wire [1:0] cpsr_aif_dsel;
wire [2:0] cpsr_aif_d_imm;
wire cpsr_mode_we;
wire [1:0] cpsr_mode_dsel;
wire [4:0] cpsr_mode_d_imm;
wire cpsr_priv;
wire spsr_we;
wire spsr_dsel;
wire ls;
wire ls_store;
wire [2:0] ls_addr_offset_sel;
wire [1:0] ls_addr_sel;
wire ls_part;
wire ls_half;
wire ls_ld_sign_ext;
wire ls_double;
wire lsm;
wire branch_ex1;
wire [1:0] branch_ex1_dest_sel;
wire [4:2] branch_ex1_dest_imm;
wire branch_wb;
wire branch_wb_dest_sel;
wire mul;
wire mul_long;
wire mul_sign;
wire mul_add;
wire [1:0] ext_rot;
wire [1:0] ext_op;
wire ext_sign;
wire ext_add;
wire coproc_sel;
wire coproc_cp_num;
wire coproc_op1;
wire coproc_op2;
wire coproc_crn;
wire coproc_crm;

instruction_decoder2 u_instruction_decoder2(
  i_pipe_instr,
  i_pipe_instr_class,
  read_rn,
  rn_sel,
  read_rd,
  rd_sel,
  rd_sel_usr,
  read_rs,
  rs_sel,
  read_rm,
  rm_sel,
  read_nzcv,
  read_spsr,
  gpr_we0,
  gpr_wa0,
  gpr_wa0_exc,
  gpr_dsel0_ex1,
  gpr_dsel0_ex2,
  gpr_dsel0_ex3,
  gpr_dsel0_wb,
  gpr_we1,
  gpr_wa1,
  gpr_wa1_usr,
  gpr_dsel1,
  cpsr_nzcv_we,
  cpsr_nzcv_dsel,
  cpsr_aif_we,
  cpsr_aif_dsel,
  cpsr_aif_d_imm,
  cpsr_mode_we,
  cpsr_mode_dsel,
  cpsr_mode_d_imm,
  cpsr_priv,
  spsr_we,
  spsr_dsel,
  ls,
  ls_store,
  ls_addr_offset_sel,
  ls_addr_sel,
  ls_part,
  ls_half,
  ls_ld_sign_ext,
  ls_double,
  lsm,
  branch_ex1,
  branch_ex1_dest_sel,
  branch_ex1_dest_imm,
  branch_wb,
  branch_wb_dest_sel,
  mul,
  mul_long,
  mul_sign,
  mul_add,
  ext_rot,
  ext_op,
  ext_sign,
  ext_add,
  coproc_sel,
  coproc_cp_num,
  coproc_op1,
  coproc_op2,
  coproc_crn,
  coproc_crm
);

popcnt u_popcnt_lsm(
        .in(i_pipe_instr[15:0]),
        .out(lsm_regcnt_tot)
);

assign read_gpr[ 0] = read_rn & o_pipe_gpr_rn_sel ==  0 | read_rm & o_pipe_gpr_rm_sel ==  0 | read_rs & o_pipe_gpr_rs_sel ==  0 | read_rd & o_pipe_gpr_rd_sel ==  0 ;
assign read_gpr[ 1] = read_rn & o_pipe_gpr_rn_sel ==  1 | read_rm & o_pipe_gpr_rm_sel ==  1 | read_rs & o_pipe_gpr_rs_sel ==  1 | read_rd & o_pipe_gpr_rd_sel ==  1 ;
assign read_gpr[ 2] = read_rn & o_pipe_gpr_rn_sel ==  2 | read_rm & o_pipe_gpr_rm_sel ==  2 | read_rs & o_pipe_gpr_rs_sel ==  2 | read_rd & o_pipe_gpr_rd_sel ==  2 ;
assign read_gpr[ 3] = read_rn & o_pipe_gpr_rn_sel ==  3 | read_rm & o_pipe_gpr_rm_sel ==  3 | read_rs & o_pipe_gpr_rs_sel ==  3 | read_rd & o_pipe_gpr_rd_sel ==  3 ;
assign read_gpr[ 4] = read_rn & o_pipe_gpr_rn_sel ==  4 | read_rm & o_pipe_gpr_rm_sel ==  4 | read_rs & o_pipe_gpr_rs_sel ==  4 | read_rd & o_pipe_gpr_rd_sel ==  4 ;
assign read_gpr[ 5] = read_rn & o_pipe_gpr_rn_sel ==  5 | read_rm & o_pipe_gpr_rm_sel ==  5 | read_rs & o_pipe_gpr_rs_sel ==  5 | read_rd & o_pipe_gpr_rd_sel ==  5 ;
assign read_gpr[ 6] = read_rn & o_pipe_gpr_rn_sel ==  6 | read_rm & o_pipe_gpr_rm_sel ==  6 | read_rs & o_pipe_gpr_rs_sel ==  6 | read_rd & o_pipe_gpr_rd_sel ==  6 ;
assign read_gpr[ 7] = read_rn & o_pipe_gpr_rn_sel ==  7 | read_rm & o_pipe_gpr_rm_sel ==  7 | read_rs & o_pipe_gpr_rs_sel ==  7 | read_rd & o_pipe_gpr_rd_sel ==  7 ;
assign read_gpr[ 8] = read_rn & o_pipe_gpr_rn_sel ==  8 | read_rm & o_pipe_gpr_rm_sel ==  8 | read_rs & o_pipe_gpr_rs_sel ==  8 | read_rd & o_pipe_gpr_rd_sel ==  8 ;
assign read_gpr[ 9] = read_rn & o_pipe_gpr_rn_sel ==  9 | read_rm & o_pipe_gpr_rm_sel ==  9 | read_rs & o_pipe_gpr_rs_sel ==  9 | read_rd & o_pipe_gpr_rd_sel ==  9 ;
assign read_gpr[10] = read_rn & o_pipe_gpr_rn_sel == 10 | read_rm & o_pipe_gpr_rm_sel == 10 | read_rs & o_pipe_gpr_rs_sel == 10 | read_rd & o_pipe_gpr_rd_sel == 10 ;
assign read_gpr[11] = read_rn & o_pipe_gpr_rn_sel == 11 | read_rm & o_pipe_gpr_rm_sel == 11 | read_rs & o_pipe_gpr_rs_sel == 11 | read_rd & o_pipe_gpr_rd_sel == 11 ;
assign read_gpr[12] = read_rn & o_pipe_gpr_rn_sel == 12 | read_rm & o_pipe_gpr_rm_sel == 12 | read_rs & o_pipe_gpr_rs_sel == 12 | read_rd & o_pipe_gpr_rd_sel == 12 ;
assign read_gpr[13] = read_rn & o_pipe_gpr_rn_sel == 13 | read_rm & o_pipe_gpr_rm_sel == 13 | read_rs & o_pipe_gpr_rs_sel == 13 | read_rd & o_pipe_gpr_rd_sel == 13 ;
assign read_gpr[14] = read_rn & o_pipe_gpr_rn_sel == 14 | read_rm & o_pipe_gpr_rm_sel == 14 | read_rs & o_pipe_gpr_rs_sel == 14 | read_rd & o_pipe_gpr_rd_sel == 14 ;

assign o_pipe_valid = i_pipe_valid ;
assign o_pipe_pc    = i_pipe_valid ? i_pc : 30'bx ;
assign o_pipe_instr = i_pipe_valid ? i_pipe_instr : 32'bx ;
assign o_pipe_retaddr = {i_pc-30'b1, 2'b0};
assign o_pipe_cond = &i_pipe_instr[31:28] ? 4'b1110 : i_pipe_instr[31:28] ;
assign o_pipe_gpr_rn_sel = rn_sel;
assign o_pipe_gpr_rd_sel = rd_sel;
assign o_pipe_gpr_rd_sel_usr = rd_sel_usr;
assign o_pipe_gpr_rs_sel = rs_sel;
assign o_pipe_gpr_rm_sel = rm_sel;
assign o_pipe_gpr_we0 = i_pipe_valid & gpr_we0;
assign o_pipe_gpr_wa0 = gpr_wa0;
assign o_pipe_gpr_wa0_exc = gpr_wa0_exc;
assign o_pipe_gpr_dsel0_ex1 = gpr_dsel0_ex1;
assign o_pipe_gpr_dsel0_ex2 = gpr_dsel0_ex2;
assign o_pipe_gpr_dsel0_ex3 = gpr_dsel0_ex3;
assign o_pipe_gpr_dsel0_wb  = gpr_dsel0_wb ;
assign o_pipe_gpr_we1 = i_pipe_valid & gpr_we1;
assign o_pipe_gpr_wa1 = gpr_wa1;
assign o_pipe_gpr_wa1_usr = gpr_wa1_usr;
assign o_pipe_gpr_dsel1 = gpr_dsel1;
assign o_pipe_alu_op = i_pipe_instr[24:21];
assign o_pipe_shifter_operand_imm = i_pipe_instr[25];
assign o_pipe_cpsr_nzcv_we = i_pipe_valid & cpsr_nzcv_we;
assign o_pipe_cpsr_nzcv_dsel = cpsr_nzcv_dsel;
assign o_pipe_cpsr_aif_we = {3{i_pipe_valid}} & cpsr_aif_we;
assign o_pipe_cpsr_aif_dsel = cpsr_aif_dsel;
assign o_pipe_cpsr_aif_d_imm = cpsr_aif_d_imm;
assign o_pipe_cpsr_mode_we = i_pipe_valid & cpsr_mode_we;
assign o_pipe_cpsr_mode_dsel = cpsr_mode_dsel;
assign o_pipe_cpsr_mode_d_imm = cpsr_mode_d_imm;
assign o_pipe_cpsr_priv = cpsr_priv;
assign o_pipe_spsr_we = i_pipe_valid & spsr_we;
assign o_pipe_spsr_dsel = spsr_dsel;
assign o_pipe_ls = i_pipe_valid & ls;
assign o_pipe_ls_store = ls_store;
assign o_pipe_ls_addr_offset_sel = ls_addr_offset_sel;
assign o_pipe_ls_addr_sel = ls_addr_sel;
assign o_pipe_ls_part = ls_part;
assign o_pipe_ls_half = ls_half;
assign o_pipe_ls_ld_sign_ext = ls_ld_sign_ext;
assign o_pipe_ls_double = ls_double;
assign o_pipe_lsm = i_pipe_valid & lsm;
assign o_pipe_lsm_reglist = i_pipe_instr[15:0] & (i_pipe_instr[15:0]-16'b1);
assign o_pipe_lsm_regcnt_tot = lsm_regcnt_tot;
assign o_pipe_lsm_regcnt_dec = lsm_regcnt_tot;
assign o_pipe_lsm_regcnt_inc = 4'b0;
assign o_pipe_branch_ex1 = i_pipe_valid & branch_ex1;
assign o_pipe_branch_ex1_dest_sel = branch_ex1_dest_sel;
assign o_pipe_branch_ex1_dest_imm = branch_ex1_dest_imm;
assign o_pipe_branch_wb = i_pipe_valid & branch_wb;
assign o_pipe_branch_wb_dest_sel = branch_wb_dest_sel;
assign o_pipe_mul = i_pipe_valid & mul;
assign o_pipe_mul_long = mul_long;
assign o_pipe_mul_sign = mul_sign;
assign o_pipe_mul_add = mul_add;
assign o_pipe_ext_rot = ext_rot;
assign o_pipe_ext_op = ext_op;
assign o_pipe_ext_sign = ext_sign;
assign o_pipe_ext_add = ext_add;
assign o_pipe_coproc_sel = coproc_sel;
assign o_pipe_coproc_cp_num = coproc_cp_num;
assign o_pipe_coproc_op1 = coproc_op1;
assign o_pipe_coproc_op2 = coproc_op2;
assign o_pipe_coproc_crn = coproc_crn;
assign o_pipe_coproc_crm = coproc_crm;

assign o_valid = i_pipe_valid;

//assign o_pipe_read_gpr = {15{i_pipe_valid}} & read_gpr;
//assign o_read_nzcv = i_pipe_valid & read_nzcv;
//assign o_read_spsr = i_pipe_valid & read_spsr;

endmodule
